package com.codemonkey.lq.extend.excelverification;

import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;

import com.codemonkey.lq.common.util.StringHelper;
import com.codemonkey.lq.extend.excelverification.impl.CustomVerifier;
import com.codemonkey.lq.extend.excelverification.impl.ExpressionVerifier;
import com.codemonkey.lq.extend.excelverification.impl.MixVerifier;
import com.codemonkey.lq.extend.excelverification.impl.NotNullableVerifier;
import com.codemonkey.lq.extend.excelverification.impl.NullableVerifier;
import com.codemonkey.lq.extend.excelverification.impl.TypeVerifier;

/**
 * 参见XMLConfigBuilder
 * @author LQ
 *
 */
public final class ConfigBuilder {
	private Config config = new Config();
	private XPathParser parser;

	public ConfigBuilder(InputStream io) {
		super();
		parser = new XPathParser(io);
	}

	public Config build() {
		parse(parser.evalNode("/fields"));
		return config;
	}

	private void parse(XNode root) {
		fieldElementList(root.evalNodes("field"));
	}

	private void fieldElementList(List<XNode> evalNodes) {
		for (int i = 0; i < evalNodes.size(); i++) {
			parseFieldInfo(evalNodes.get(i), i);
		}
	}

	/**
	 * @param fieldInfoNode
	 * @param index 该fieldInfoNode位于集合中的索引
	 */
	private void parseFieldInfo(XNode fieldInfoNode, int index) {

		final MixVerifier mixVerifier = new MixVerifier();

		// 必须是第一个,是否可为空的判断, 如果用户进行了配置的话
		nullableValidate(fieldInfoNode, mixVerifier);
		// 然后进行类型校验, 如果用户进行了配置的话
		typeValidate(fieldInfoNode, mixVerifier);
		parserExpressValidate(fieldInfoNode, mixVerifier);
		parserCustomValidate(fieldInfoNode, mixVerifier);

		config.register(fieldInfoNode.getStringAttribute("name"), mixVerifier);
	}

	private void nullableValidate(XNode fieldInfoNode, MixVerifier mixVerifier) {
		final String nullable = fieldInfoNode.getStringAttribute("nullable", "");
		if (StringHelper.isEmpty(nullable)) {
			return;
		}

		if (nullable.equals("true")) {
			mixVerifier.addVerifier(new NullableVerifier());
		}else{
			mixVerifier.addVerifier(new NotNullableVerifier());
		}
		
	}

	private void typeValidate(XNode fieldInfoNode, MixVerifier mixVerifier) {
		final String type = fieldInfoNode.getStringAttribute("type", "String");

		if (type.equalsIgnoreCase("String")) {
			mixVerifier.addVerifier(new TypeVerifier.StringVerifier());
		} else if (type.equalsIgnoreCase("Float")) {
			mixVerifier.addVerifier(new TypeVerifier.FloatVerifier());
		} else if (type.equalsIgnoreCase("Integer")) {
			mixVerifier.addVerifier(new TypeVerifier.IntegerVerifier());
		} else if (type.equalsIgnoreCase("Date")) {
			final String pattern = fieldInfoNode.getStringAttribute("pattern");
			mixVerifier.addVerifier(TypeVerifier.DateVerifier.of(pattern));
		} else if (type.equalsIgnoreCase("Boolean")) {
			final String trueFlags = fieldInfoNode.getStringAttribute("trueFlags");
			mixVerifier.addVerifier(TypeVerifier.BooleanVerifier.of(trueFlags));
		}
	}

	private void parserExpressValidate(XNode fieldInfoNode, MixVerifier mixVerifier) {
		List<XNode> expressionValidateNodeList = fieldInfoNode.evalNodes("expressionValidate");
		if (null == expressionValidateNodeList || expressionValidateNodeList.size() == 0) {
			return;
		}

		for (XNode expressionValidateNode : expressionValidateNodeList) {
			final String expression = expressionValidateNode.getStringAttribute("expression");
			final String failMsg = expressionValidateNode.getStringAttribute("failMsg");

			mixVerifier.addVerifier(new ExpressionVerifier(expression, failMsg));
		}

	}

	private void parserCustomValidate(XNode fieldInfoNode, MixVerifier mixVerifier) {
		List<XNode> customValidateNodeList = fieldInfoNode.evalNodes("customValidate");
		if (null == customValidateNodeList || customValidateNodeList.size() == 0) {
			return;
		}

		for (XNode customValidateNode : customValidateNodeList) {
			final String clsString = customValidateNode.getStringAttribute("class");

			mixVerifier.addVerifier(new CustomVerifier(clsString));
		}
	}

}
